package httpcommon

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	lg "gitee.com/bm_guangge/bm_common/log"
	"github.com/PuerkitoBio/goquery"
)

var timeoutValue = time.Minute

func SendHttpPost(url string, in interface{}) (string, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	js, err := json.Marshal(in)
	if err != nil {
		lg.ELogger.Println("json err:", err)
		return "", err
	}
	lg.ILogger.Println("SendHttp url:", url, "json:", string(js))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

func SendHttpPostH(url string, in interface{}, hk []string, hv []string) (string, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	js, err := json.Marshal(in)
	if err != nil {
		lg.ELogger.Println("json err:", err)
		return "", err
	}
	lg.ILogger.Println("SendHttp url:", url, "json:", string(js))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	if len(hk) != len(hv) {
		return "", errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

func SendHttpPostBinary(url string, in []byte) (string, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	lg.ILogger.Println("SendHttp url:", url, "data length:", len(in))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

func SendHttpPostBinaryH(url string, in []byte, hk []string, hv []string) (string, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	lg.ILogger.Println("SendHttp url:", url, "data length:", len(in))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	if len(hk) != len(hv) {
		return "", errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

func SendHttpPostBinaryHeader(url string, in []byte, hk []string, hv []string) (string, http.Header, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	lg.ILogger.Println("SendHttp url:", url, "data length:", len(in), "data:", string(in))
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", http.Header{}, err
	}

	if len(hk) != len(hv) {
		return "", http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return "", http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), resp.Header, nil
}

func SendHttpPostBinaryHeaderB(url string, in []byte, hk []string, hv []string) ([]byte, http.Header, error) {

	// url := "http://192.168.2.235:1211/api/device/offline"
	lg.ILogger.Println("SendHttp url:", url, "data length:", len(in), "data:", string(in))
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return []byte{}, http.Header{}, err
	}

	if len(hk) != len(hv) {
		return []byte{}, http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return []byte{}, http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return []byte{}, http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return bs, resp.Header, nil
}

// post form-data
func SendHttpPostFormHeader(url string, in io.Reader, hk []string, hv []string) ([]byte, http.Header, error) {

	lg.ILogger.Println("SendHttpPostFormHeader url:", url)
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("POST", url, in)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return []byte{}, http.Header{}, err
	}

	if len(hk) != len(hv) {
		return []byte{}, http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return []byte{}, http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return []byte{}, http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return bs, resp.Header, nil
}

func SendHttpGet(url string, hk, hv []string) (string, error) {

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	if len(hk) != len(hv) {
		return "", errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

func SendHttpGetTimeout(url string, hk, hv []string, seconds int64) (string, error) {

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	if len(hk) != len(hv) {
		return "", errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: time.Duration(seconds) * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return "", err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), nil
}

// 返回数据和头的get请求
func SendHttpGetHeader(url string, hk, hv []string) (string, http.Header, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", http.Header{}, err
	}

	if len(hk) != len(hv) {
		return "", http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return "", http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return "", http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return string(bs), resp.Header, nil
}

// 返回数据和头的get请求
func SendHttpGetHeaderBs(url string, hk, hv []string) ([]byte, http.Header, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return []byte{}, http.Header{}, err
	}

	if len(hk) != len(hv) {
		return []byte{}, http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return []byte{}, http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return []byte{}, http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return bs, resp.Header, nil
}

func SendHttpGetQ(url string, hk, hv []string) (*goquery.Document, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return nil, err
	}

	if len(hk) != len(hv) {
		return nil, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return nil, err
	}

	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		// log.Fatal(err)
		return nil, err
	}

	return doc, nil
}

// 返回数据和头的get请求
func SendHttpGetHeaderQ(url string, hk, hv []string) (*goquery.Document, http.Header, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return nil, http.Header{}, err
	}

	if len(hk) != len(hv) {
		return nil, http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("get:", err)
		return nil, http.Header{}, err
	}

	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		// log.Fatal(err)
		return nil, http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return doc, resp.Header, nil
}

// 下载内容到文件
func SendHttpGetFile(url, filepath string, hk, hv []string) error {
	lg.ILogger.Println("start download ", filepath)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return err
	}

	if len(hk) != len(hv) {
		return errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: 20 * timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		lg.ELogger.Println("get:", err)
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusForbidden {
		return errors.New("禁止访问")
	}

	// 请求报错
	if resp.StatusCode != http.StatusOK {
		bs, _ := ioutil.ReadAll(resp.Body)
		return errors.New(string(bs))
	}

	if filepath != "" {
		// 创建文件
		out, err := os.Create(filepath)
		if err != nil {
			lg.ELogger.Println("Create", filepath, "error")
			return err
		}
		defer out.Close()

		_, err = io.Copy(out, resp.Body)
		if err != nil {
			lg.ELogger.Println("Copy file error:", err.Error())
			return err
		}
	}

	return nil
}

// 下载内容到文件,文件不带后缀的,需要通过http请求返回的头 找到content-disposition的内容确定后缀
func SendHttpGetFileNoSuffix(url, filepath string, hk, hv []string) (string, error) {
	lg.ILogger.Println("start download ", filepath)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return "", err
	}

	if len(hk) != len(hv) {
		return "", errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: 20 * timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		lg.ELogger.Println("get:", err)
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusForbidden {
		return "", errors.New("禁止访问")
	}
	// 请求报错
	if resp.StatusCode != http.StatusOK {
		bs, _ := ioutil.ReadAll(resp.Body)
		return "", errors.New(string(bs))
	}

	cds := resp.Header.Get("content-disposition")
	cdss := strings.Split(cds, "; ")
	suffix := ""
	for _, d := range cdss {
		dd := strings.Split(d, "=")
		if len(dd) == 2 && dd[0] == "filename" {
			ddd := strings.Split(dd[1], ".")
			if len(ddd) > 1 {
				suffix = ddd[len(ddd)-1]
				suffix = strings.TrimSuffix(suffix, "\"")
			}
		}
	}

	fp := filepath
	if suffix != "" {
		fp = fmt.Sprintf("%s.%s", filepath, suffix)
	}

	// 创建文件
	out, err := os.Create(fp)
	if err != nil {
		lg.ELogger.Println("Create", fp, "error")
		return "", err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		lg.ELogger.Println("Copy file error:", err.Error())
		return "", err
	}

	return suffix, nil
}

func SendHttpPut(url string, in []byte, hk, hv []string) error {
	lg.ILogger.Println("SendHttpPut url:", url, "data length:", len(in))
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("PUT", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return err
	}

	if len(hk) != len(hv) {
		return errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}
	// req.Header.Set("Content-Type", "application/octet-stream")

	client := &http.Client{Timeout: timeoutValue}
	_, err = client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return err
	}

	// defer resp.Body.Close()
	// // 一次性读取
	// bs, err := ioutil.ReadAll(resp.Body)
	// if err != nil {
	// 	lg.ILogger.Println("read:", err)
	// 	return err
	// }
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return nil
}

func SendHttpPutHeader(url string, in []byte, hk, hv []string) (http.Header, error) {
	lg.ILogger.Println("SendHttpPut url:", url, "data length:", len(in))
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("PUT", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return http.Header{}, err
	}

	if len(hk) != len(hv) {
		return http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return http.Header{}, err
	}

	return resp.Header, nil
}

func SendHttpPutHeaderBs(url string, in []byte, hk, hv []string) ([]byte, http.Header, error) {
	lg.ILogger.Println("SendHttpPut url:", url, "data length:", len(in))
	lg.ILogger.Println("hk:", hk, "hv:", hv)
	req, err := http.NewRequest("PUT", url, bytes.NewBuffer(in))
	if err != nil {
		lg.ELogger.Println("NewRequest:", err)
		return []byte{}, http.Header{}, err
	}

	if len(hk) != len(hv) {
		return []byte{}, http.Header{}, errors.New("head参数错误")
	}

	for i, k := range hk {
		req.Header.Set(k, hv[i])
	}

	client := &http.Client{Timeout: timeoutValue}
	resp, err := client.Do(req)
	if err != nil {
		// panic(err)
		lg.ELogger.Println("post:", err)
		return []byte{}, http.Header{}, err
	}

	defer resp.Body.Close()
	// 一次性读取
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		lg.ILogger.Println("read:", err)
		return []byte{}, http.Header{}, err
	}
	// lg.ILogger.Println("SendHttp result:", string(bs))

	return bs, resp.Header, nil
}

// 返回 Content-Type, body部分 该接口和SendHttpPostFormHeader配合使用
func CreateFormRequestBody(ds map[string]string, filePath string) (string, io.Reader, error) {
	buf := new(bytes.Buffer)
	bw := multipart.NewWriter(buf)

	for k, v := range ds {
		p, _ := bw.CreateFormField(k)
		p.Write([]byte(v))
	}

	// 如果文件名不为空，传输文件
	if filePath != "" {
		f, err := os.Open(filePath)
		if err != nil {
			return "", nil, err
		}
		defer f.Close()
		_, nm := filepath.Split(filePath)
		fw, _ := bw.CreateFormFile("file", nm)
		io.Copy(fw, f)
	}
	bw.Close()

	return bw.FormDataContentType(), buf, nil
}
